//! @Author: DengLibin 
//! @Date:  2022-04-20 19:46:20
//! @Description:
use std::{io, sync::{Mutex, atomic::AtomicUsize}, cell::Cell};

use actix_files::Files;
use actix_web::{
    error,
    http::{header, StatusCode, self},
    middleware::{self, ErrorHandlers},
    web::{self, Data},
    App, HttpRequest, HttpResponse, HttpServer,
};
use actix_session::CookieSession;

use crate::controller::sys_controller;
use crate::controller::user_controller;
use crate::controller::error_controller;
use crate::controller::state_controller;
use crate::sys;
use crate::config::app_config::config_app;
use crate::middleware::error_handle;

static SESSION_SIGNING_KEY: &[u8] = &[0; 32];
// async fn index(req: HttpRequest) -> &'static str {
//     println!("REQ: {:?}", req);
//     "Hello world!"
// }

/// @Author: DengLibin 
/// @Date:  2022-04-20 19:53:37
/// @Description: 开启web服务器
pub async fn run() -> std::io::Result<()> {
    //初始化
    info!("初始化...");
    sys::init();
    // Create some global state prior to building the server
    //创建一些全局状态 放到闭包外面
    #[allow(clippy::mutex_atomic)] // it's intentional.
        //全局计数器，非线程安全 使用锁
        let counter_mutex = Data::new(Mutex::new(0_usize));
    //全局计数器，使用原子操作
    let counter_atomic = Data::new(AtomicUsize::new(0_usize));
    info!("创建HttpServer");
    let http_server = HttpServer::new(move || {
        // Create some thread-local state 
        // 线程本地状态（放到闭包内部，线程安全，设置了多少个工作线程，就有多个）
        let counter_cell = Cell::new(0u32);
        let session_store = CookieSession::signed(SESSION_SIGNING_KEY).secure(false);

        //错误捕捉
        let error_handlers = ErrorHandlers::new()
            .handler(
                http::StatusCode::INTERNAL_SERVER_ERROR,
                error_handle::internal_server_error,
            )
            .handler(http::StatusCode::BAD_REQUEST, error_handle::bad_request)
            .handler(http::StatusCode::NOT_FOUND, error_handle::not_found);

        info!("创建App");
        let app = App::new()

            // 压缩response 通常放到第一个
            .wrap(middleware::Compress::default())
            // cookie session middleware
            .wrap(session_store)
            // enable logger 通常放到最后
            .wrap(middleware::Logger::default())
            .wrap(error_handlers)

            .configure(config_app)
            .service(web::resource("/index.html").to(|| async { "Hello world!" }))
            //.service(web::resource("/").to(index))
            //服务端错误
            .service(web::resource("/error").to(|| async {
                error::InternalError::new(
                    io::Error::new(io::ErrorKind::Other, "500 服务端错误"),
                    StatusCode::INTERNAL_SERVER_ERROR,
                )
            }))
            //静态资源路径
            .service(Files::new("static", "static").show_files_listing())
            //重定向
            .service(
                web::resource("/").route(web::get().to(|_: HttpRequest| async move {
                    //println!("{:?}", req);
                    HttpResponse::Found()
                        .insert_header((header::LOCATION, "static/welcome.html"))
                        .finish()
                })),
            )
            .service(sys_controller::favicon)
            .service(sys_controller::welcome)
            .service(sys_controller::time)
            // async response body
            .service(web::resource("/async-body/{name}").route(web::get().to(sys_controller::response_body)))
            .service(web::resource("/something").route(web::get().to(error_controller::do_something)))
            .service(user_controller::get_user)
            .service(user_controller::get_user_param)
            //设置全局数据
            .app_data(counter_mutex.clone()) // add shared state
            .app_data(counter_atomic.clone()) // add shared state
            .app_data(Data::new(counter_cell)) // add thread-local state 
            .service(state_controller::index)
            .service(state_controller::index2)

            .default_service(web::to(sys_controller::default_handler));
        return app;
    });
    info!("创建HttpServer完成");
    info!("绑定端口:{}启动,", 8080);
    http_server.bind(("127.0.0.1", 8080))?
        .workers(2) //工作线程数 默认cpu数量
        .run()
        .await
}
